{
	// 定义一个描述对象的类型，规定这种类型的对象必须由类型的属性
	/* type Animal = {
		name: string;
		age: number;
		sayHello(): void;
	}; */

	// 定义一个Animal接口
	/*
	 * 接口用来定义一个类结构，用来定义一个类中应该包含哪些属性和方法
	 * 同时接口也可以当成类型声明去使用
	 * 接口可以在定义类的时候去限制类的结构，
	 * 接口中的所有的属性都不能有实际的值
	 * 接口只定义对象的结构，而不考虑实际值
	 * 在接口中所有的方法都是抽象方法
	 */
	interface Animal {
		name: string;
		age: number;
		sayHello (): void;
	}

	// 所有的类和接口都可以作为类型给变量声明
	/* const obj: Animal = {
		name: '猫',
		age: 3,
		sayHello() {
			console.log('喵喵喵');
		},
	}; */

	/*
	 * 定义类时，使用implements 使类去实现一个接口,
	 *   实现接口就是使类满足接口的要求
	 */
	class Dog implements Animal {
		// 定义实例属性
		name: string;
		age: number;
		species: string;

		// 如果在子类中写了构造函数，在子类构造函数中"必须"对父类的构造函数进行调用
		constructor(name: string, age: number, species: string) {
			// 使用super调用父类的构造函数，super就表示当前类的父类
			// 接口没有构造函数
			// super(name, age);
			this.name = name;
			this.age = age;
			this.species = species;
		}

		sayHello() {
			console.log('汪汪汪~');
		}

		run() {
			console.log(`${this.name}在跑`);
		}
	}

	// 接口不能用来实例化
	// const animal = new Animal(); //报错：“Animal”仅表示类型，但在此处却作为值使用

	const dog = new Dog('小黑', 3, '柯基');

	console.log(dog);
	dog.sayHello();
	dog.run();

	/* 使用接口的方式来定义一个函数需要符合的形状 */
	interface SearchFunc {
		(source: string, subString: string): boolean;
	}

	let mySearch: SearchFunc;
	mySearch = function (source: string, subString: string) {
		return source.search(subString) !== -1;
	};
}
